package android.itv.controller;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.WeakHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import android.app.Activity;
import android.app.AlarmManager;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.itv.R;
import android.itv.controller.BroadcastScheduleController.CustomeAdapterForListSchedule;
import android.itv.library.Database;
import android.itv.library.JsonPrase;
import android.itv.library.ServiceHelper;
import android.itv.model.BroadcastSchedule;
import android.itv.model.Channel;
import android.itv.model.IChannel;
import android.itv.model.Notification;
import android.itv.view.Main;
import android.itv.view.ViewTivi;
import android.os.AsyncTask;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Gallery;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.TimePicker;

public class ChannelController extends Activity implements IChannel
{
    Gallery gallery;
    ListView listView;
    Context context;
    Button btnWatch,btnDate;
    TextView txtTitle;
    CustomeAdapterForListChannels adapterChannel;
    ImageButton imgLoadSchedule,btnHome;
    CustomeAdapterForListSchedule adapterSchedule;
    ProgressBar progressBar;
    TextView txtempty;
    @Override
    public ArrayList<Channel> loadChannelsFromService()
    {
	return null;
    }
    
    public ChannelController(ListView listView,Gallery gallery,Button btnWatch,Button btnDate,final ImageButton imgLoadSchedule, final ProgressBar progressBar,final TextView txtTitle,ImageButton btnHome,TextView txtempty,Context context)
    {
	this.context=context;
	
	this.listView=listView;
	this.gallery=gallery;
	this.btnWatch=btnWatch;
	this.btnDate=btnDate;
	this.imgLoadSchedule=imgLoadSchedule;
	this.progressBar=progressBar;
	this.txtTitle=txtTitle;
	this.btnHome=btnHome;
	this.txtempty=txtempty;
    }
    
    public ChannelController()
    {
	
    }
    @Override
    public void loadChannelsToView(ArrayList<Channel> listChannels)
    {
	final String date;
	final String month;
	final String year;
	
	
	Calendar calendar=Calendar.getInstance(Locale.US);
	String day=calendar.getDisplayName(Calendar.DAY_OF_WEEK,Calendar.LONG,Locale.US).toString();
	date=calendar.get(Calendar.DAY_OF_MONTH)+"";
	month=String.valueOf(calendar.get(Calendar.MONTH)+1);
	year=calendar.get(Calendar.YEAR)+"";
	
	btnDate.setText(day+", "+android.itv.library.Utils.getDate(date, month, year));
	adapterChannel=new CustomeAdapterForListChannels(listChannels, context);
	gallery.setAdapter(adapterChannel);
	gallery.setOnItemClickListener(new OnItemClickListener()
	{
	    @Override
            public void onItemClick(AdapterView<?> arg0, View arg1, final int arg2, long arg3)
            {
		final String idChannel=adapterChannel.listChannels.get(arg2).getIdChannel();
		txtTitle.setText(adapterChannel.listChannels.get(arg2).getName());
		Database db=new Database(context);
		BroadcastSchedule bs=db.loadBroadcastSchedule(idChannel, android.itv.library.Utils.getDate(date, month, year));
		
		//neu co lich trong DB roi thi se load tu DB len
		if(bs.getListprograme().size()>=1)
		{
		    imgLoadSchedule.setVisibility(View.INVISIBLE);
		    progressBar.setVisibility(View.INVISIBLE);
		    txtempty.setVisibility(View.INVISIBLE);
		    loadBroadcastSchedulesFromDBToView(bs, context);
		}
		//neu khong thi se lay tu service
		else
		{
		    clearListView();
		    imgLoadSchedule.setVisibility(View.VISIBLE);
		    if(imgLoadSchedule.isShown()) 
		    {	
			progressBar.setVisibility(View.INVISIBLE);
		    	txtempty.setVisibility(View.INVISIBLE);
		    }
		    
		    imgLoadSchedule.setOnClickListener(new OnClickListener()
			{
			    
			    @Override
			    public void onClick(View v)
			    {
				progressBar.setVisibility(View.VISIBLE);
				imgLoadSchedule.setVisibility(View.INVISIBLE);
				new LoadScheduleFromService(txtTitle).execute(adapterChannel.listChannels.get(arg2).getName(),adapterChannel.listChannels.get(arg2).getIdChannel(),android.itv.library.Utils.getDate(date, month, year));
			    }
			});
		    btnWatch.setOnClickListener(new OnClickListener()
			{
			    
			    @Override
			    public void onClick(View v)
			    {
				Intent intent=new Intent(context,ViewTivi.class);
				intent.putExtra("URL",adapterChannel.listChannels.get(arg2).getLinktv());
				Log.d("URL",adapterChannel.listChannels.get(arg2).getLinktv());
				context.startActivity(intent);
			    }
			});
		}
            }
	});
	
	btnHome.setOnClickListener(new OnClickListener()
	{
	    
	    @Override
	    public void onClick(View v)
	    {
		Intent intent=new Intent(context,Main.class);
		intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
		context.startActivity(intent);
	    }
	});
	
	
    }
    
    public CustomeAdapterForListSchedule loadBroadcastSchedulesFromServiceToView(String idChannel, String date)
    {
	BroadcastSchedule bs=new  BroadcastSchedule();
	String schedule=new ServiceHelper(context).getSchedule(idChannel, date);
	bs.setDate(date);
	bs.setIdChannel(idChannel);
	bs.setListprograme(JsonPrase.parseSchedule(schedule));
	CustomeAdapterForListSchedule adapter=new BroadcastScheduleController().new CustomeAdapterForListSchedule(context, bs);
	Log.d("SAVE","SAVE");
	//save schedule vao database
	 final Database db=new Database(context);
	 db.saveBroadcastSchedule(idChannel, date, schedule);
	// 
	return adapter;
    }
    
    public void loadBroadcastSchedulesFromDBToView (final BroadcastSchedule bs,final Context context)
    {
	 adapterSchedule=new BroadcastScheduleController().new CustomeAdapterForListSchedule(context, bs);

	 listView.setAdapter(adapterSchedule);
	 listView.setSelection(android.itv.library.Utils.getProgramePlayedNow(bs)); 
	 listView.setOnItemClickListener(new OnItemClickListener()
	{
	     @Override
	    public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3)
	    {
		int hour, minute;
		String content="";
		String time=bs.getListprograme().get(arg2).getTime();
		String nameChannel="";
		Database db=new Database(context);
		nameChannel=db.getNameChannel(bs.getIdChannel());
		hour=android.itv.library.Utils.getHour(time);
		minute=android.itv.library.Utils.getMinute(time);
		content=nameChannel+"-"+time+"-"+bs.getListprograme().get(arg2).getTitle()+"\n"+bs.getListprograme().get(arg2).getDescription();
		createDialog(hour,minute,content,nameChannel);
	    }
	});
    }
    
    public void clearListView()
    {
	if(adapterSchedule!=null)
	{
        	if(adapterSchedule.broadSchedule.getListprograme().size()>0)
        	{
        	    adapterSchedule.broadSchedule.getListprograme().clear();
        	    adapterSchedule.notifyDataSetChanged();
        	}
	}
    }
    
  
    
    private class LoadScheduleFromService extends AsyncTask<String,Void, CustomeAdapterForListSchedule>
    {
	private TextView txtTitle;
	private String txt="";
	public  LoadScheduleFromService(TextView txtTitle)
        {
	    this.txtTitle=txtTitle;
        }
	@Override
        protected CustomeAdapterForListSchedule doInBackground(final String... params)
        {	
	    BroadcastSchedule bs=new BroadcastSchedule();
	   txt=params[0];
	   try
	   {
	       adapterSchedule=loadBroadcastSchedulesFromServiceToView(params[1],params[2]);
	   }
	   catch (Exception e) 
	   {
	      adapterSchedule=new BroadcastScheduleController().new CustomeAdapterForListSchedule(context, bs);
	       
	   }
	   return adapterSchedule;
        }
	
	@Override
	protected void onPostExecute(final CustomeAdapterForListSchedule adapter)
	{
	    if(txtTitle.getText().toString().compareToIgnoreCase(txt)==0)
	    {
		if(adapter.getCount()!=0)
		{
		    listView.setAdapter(adapter);
		    txtempty.setVisibility(View.INVISIBLE);
		}
		else
		{
		    txtempty.setVisibility(View.VISIBLE);
		}
		 runOnUiThread(new Runnable()
		    {
		      	public void run()
		        {
		            txtTitle.setText(txt);
		        }
		    });

	    }
	    imgLoadSchedule.setVisibility(View.INVISIBLE);
	    progressBar.setVisibility(View.INVISIBLE);
	    
	    final BroadcastSchedule br=adapter.broadSchedule;
	    final Database db=new Database(context);
	    
	    listView.setOnItemClickListener(new OnItemClickListener()
	    {

		@Override
                public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3)
                {
		    	int hour, minute;
			String content="";
					
			String time=br.getListprograme().get(arg2).getTime();
			String nameChannel="";
			
			nameChannel=db.getNameChannel(br.getIdChannel());
			hour=android.itv.library.Utils.getHour(time);
			
			minute=android.itv.library.Utils.getMinute(time);
			content=nameChannel+"-"+time+"-"+br.getListprograme().get(arg2).getTitle()+"\n"+br.getListprograme().get(arg2).getDescription();
			createDialog(hour,minute,content,nameChannel);                }
	    });
	}
    }
    
    private void createDialog(int hour,int minute,final String content,final String nameChannel)
    {
	AlertDialog.Builder builder = new AlertDialog.Builder(context);
	AlertDialog dialog;
	final TimePicker tp;
	final EditText edtContentNotify;
	
	LayoutInflater inflater=(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
	View view=inflater.inflate(R.layout.dialogsettime, null);
	tp=(TimePicker)view.findViewById(R.id.timePicker);
	edtContentNotify=(EditText)view.findViewById(R.id.edtcontentNofify);
	
	builder.setView(view);	
	tp.setIs24HourView(true);
	tp.setCurrentHour(hour);
	tp.setCurrentMinute(minute);
	edtContentNotify.setText(content);
	
	builder.setTitle(R.string.timetonotification);
	builder.setIcon(R.drawable.ic_launcher);
	builder.setPositiveButton(R.string.btnpositive, new DialogInterface.OnClickListener()
	{
	    
	    @Override
	    public void onClick(DialogInterface dialog, int which)
	    {		
		int hour=tp.getCurrentHour();
		int minute=tp.getCurrentMinute();
		Calendar cal=Calendar.getInstance();
		cal.set(Calendar.HOUR_OF_DAY, hour);
		cal.set(Calendar.MINUTE,minute);
		cal.set(Calendar.SECOND, 0);	
		AlarmManager alarmM=(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
		NotificationController notificationController=new NotificationController();
		notificationController.setNotification(context, alarmM,cal.getTimeInMillis(),edtContentNotify.getText().toString());
		int month=cal.get(cal.get(Calendar.MONTH))+1;
		String time=cal.get(Calendar.DAY_OF_MONTH)+"/"+month+"/"+cal.get(Calendar.YEAR)+", "+hour+"h"+minute;
		Notification notification=new Notification(nameChannel, time, edtContentNotify.getText().toString());
		
		NotificationController notiController=new NotificationController(context);
		notiController.saveNotificationDB(notification);
	    }
	});
	
	builder.setNegativeButton(R.string.btnnegative, new DialogInterface.OnClickListener()
	{
	    
	    @Override
	    public void onClick(DialogInterface dialog, int which)
	    {
		
	    }
	});
	
	dialog=builder.create();
	dialog.show();
    }
    
    
    private class CustomeAdapterForListChannels extends BaseAdapter
    {
	public ArrayList<Channel> listChannels;
	private Context context;
	private LayoutInflater inflater;
	private ImageLoader imageLoader; 
	
	public CustomeAdapterForListChannels(ArrayList<Channel> listChannels, Context context)
	{
	    this.listChannels = listChannels;
	    this.context = context;
	    inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
	    imageLoader=new ImageLoader(context);
	}
	
	@Override
	public int getCount()
	{
	    return listChannels.size();
	}
	
	@Override
	public Object getItem(int arg0)
	{
	    return arg0;
	}
	
	@Override
	public long getItemId(int arg0)
	{
	    return arg0;
	}
	
	@Override
	public View getView(int position, View convertView, ViewGroup arg2)
	{
	    View vi=convertView;
	    if (vi == null)
	    {
		vi = inflater.inflate(R.layout.customeadapterforlistchannels, null);
	    }
	    
	    ImageView imgchannel = (ImageView) vi.findViewById(R.id.imgchannel);
	    imageLoader.DisplayImage(listChannels.get(position).getLinkLogo(), imgchannel);
	    Log.d("Link",position + "	"+listChannels.get(position).getLinkLogo());
	    return vi;
	}
	
    }
    
    public static class Utils
    {
	public static void CopyStream(InputStream is, OutputStream os)
	{
	    final int buffer_size = 1024;
	    try
	    {
		byte[] bytes = new byte[buffer_size];
		for (;;)
		{
		    int count = is.read(bytes, 0, buffer_size);
		    if (count == -1)
			break;
		    os.write(bytes, 0, count);
		}
	    }
	    catch (Exception ex)
	    {
	    }
	}
    }
    
    public class MemoryCache
    {
	
	private static final String TAG = "MemoryCache";
	private Map<String, Bitmap> cache = Collections.synchronizedMap(new LinkedHashMap<String, Bitmap>(10, 1.5f, true));// Last
	                                                                                                                   // ordering
	private long size = 0;// current allocated size
	private long limit = 1000000;// max memory in bytes
	
	public MemoryCache()
	{
	    // use 25% of available heap size
	    setLimit(Runtime.getRuntime().maxMemory() / 4);
	}
	
	public void setLimit(long new_limit)
	{
	    limit = new_limit;
	    Log.i(TAG, "MemoryCache will use up to " + limit / 1024. / 1024. + "MB");
	}
	
	public Bitmap get(String id)
	{
	    if (!cache.containsKey(id))
		return null;
	    return cache.get(id);
	}
	
	public void put(String id, Bitmap bitmap)
	{
	    try
	    {
		if (cache.containsKey(id))
		    size -= getSizeInBytes(cache.get(id));
		cache.put(id, bitmap);
		size += getSizeInBytes(bitmap);
		checkSize();
	    }
	    catch (Throwable th)
	    {
		th.printStackTrace();
	    }
	}
	
	private void checkSize()
	{
	    Log.i(TAG, "cache size=" + size + " length=" + cache.size());
	    if (size > limit)
	    {
		Iterator<Entry<String, Bitmap>> iter = cache.entrySet().iterator();// least
		                                                                   // recently
		                                                                   // accessed
		                                                                   // item
		                                                                   // will
		                                                                   // be
		                                                                   // the
		                                                                   // first
		                                                                   // one
		                                                                   // iterated
		while (iter.hasNext())
		{
		    Entry<String, Bitmap> entry = iter.next();
		    size -= getSizeInBytes(entry.getValue());
		    iter.remove();
		    if (size <= limit)
			break;
		}
		Log.i(TAG, "Clean cache. New size " + cache.size());
	    }
	}
	
	public void clear()
	{
	    cache.clear();
	}
	
	long getSizeInBytes(Bitmap bitmap)
	{
	    if (bitmap == null)
		return 0;
	    return bitmap.getRowBytes() * bitmap.getHeight();
	}
    }
    
    public class ImageLoader
    {
	
	MemoryCache memoryCache = new MemoryCache();
	FileCache fileCache;
	private Map<ImageView, String> imageViews = Collections.synchronizedMap(new WeakHashMap<ImageView, String>());
	ExecutorService executorService;
	
	public ImageLoader(Context context)
	{
	    fileCache = new FileCache(context);
	    executorService = Executors.newFixedThreadPool(5);
	}
	
	final int stub_id =R.drawable.no_img;
	
	public void DisplayImage(String url, ImageView imageView)
	{
	    imageViews.put(imageView, url);
	    Bitmap bitmap = memoryCache.get(url);
	    if (bitmap != null)
		imageView.setImageBitmap(bitmap);
	    else
	    {
		queuePhoto(url, imageView);
		imageView.setImageResource(stub_id);
	    }
	}
	
	private void queuePhoto(String url, ImageView imageView)
	{
	    PhotoToLoad p = new PhotoToLoad(url, imageView);
	    executorService.submit(new PhotosLoader(p));
	}
	
	private Bitmap getBitmap(String url)
	{
	    File f = fileCache.getFile(url);
	    
	    // from SD cache
	    Bitmap b = decodeFile(f);
	    if (b != null)
		return b;
	    
	    // from web
	    try
	    {
		Bitmap bitmap = null;
		URL imageUrl = new URL(url);
		HttpURLConnection conn = (HttpURLConnection) imageUrl.openConnection();
		conn.setConnectTimeout(30000);
		conn.setReadTimeout(30000);
		conn.setInstanceFollowRedirects(true);
		InputStream is = conn.getInputStream();
		OutputStream os = new FileOutputStream(f);
		Utils.CopyStream(is, os);
		os.close();
		bitmap = decodeFile(f);
		return bitmap;
	    }
	    catch (Exception ex)
	    {
		ex.printStackTrace();
		return null;
	    }
	}
	
	// decodes image and scales it to reduce memory consumption
	private Bitmap decodeFile(File f)
	{
	    try
	    {
		// decode image size
		BitmapFactory.Options o = new BitmapFactory.Options();
		o.inJustDecodeBounds = true;
		BitmapFactory.decodeStream(new FileInputStream(f), null, o);
		
		// Find the correct scale value. It should be the power of 2.
		final int REQUIRED_SIZE = 70;
		int width_tmp = o.outWidth, height_tmp = o.outHeight;
		int scale = 1;
		while (true)
		{
		    if (width_tmp / 2 < REQUIRED_SIZE || height_tmp / 2 < REQUIRED_SIZE)
			break;
		    width_tmp /= 2;
		    height_tmp /= 2;
		    scale *= 2;
		}
		
		// decode with inSampleSize
		BitmapFactory.Options o2 = new BitmapFactory.Options();
		o2.inSampleSize = scale;
		return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
	    }
	    catch (FileNotFoundException e)
	    {
	    }
	    return null;
	}
	
	// Task for the queue
	private class PhotoToLoad
	{
	    public String url;
	    public ImageView imageView;
	    
	    public PhotoToLoad(String u, ImageView i)
	    {
		url = u;
		imageView = i;
	    }
	}
	
	class PhotosLoader implements Runnable
	{
	    PhotoToLoad photoToLoad;
	    
	    PhotosLoader(PhotoToLoad photoToLoad)
	    {
		this.photoToLoad = photoToLoad;
	    }
	    
	    @Override
	    public void run()
	    {
		if (imageViewReused(photoToLoad))
		    return;
		Bitmap bmp = getBitmap(photoToLoad.url);
		memoryCache.put(photoToLoad.url, bmp);
		if (imageViewReused(photoToLoad))
		    return;
		BitmapDisplayer bd = new BitmapDisplayer(bmp, photoToLoad);
		Activity a = (Activity) photoToLoad.imageView.getContext();
		a.runOnUiThread(bd);
	    }
	}
	
	boolean imageViewReused(PhotoToLoad photoToLoad)
	{
	    String tag = imageViews.get(photoToLoad.imageView);
	    if (tag == null || !tag.equals(photoToLoad.url))
		return true;
	    return false;
	}
	
	// Used to display bitmap in the UI thread
	class BitmapDisplayer implements Runnable
	{
	    Bitmap bitmap;
	    PhotoToLoad photoToLoad;
	    
	    public BitmapDisplayer(Bitmap b, PhotoToLoad p)
	    {
		bitmap = b;
		photoToLoad = p;
	    }
	    
	    public void run()
	    {
		if (imageViewReused(photoToLoad))
		    return;
		if (bitmap != null)
		    photoToLoad.imageView.setImageBitmap(bitmap);
		else
		    photoToLoad.imageView.setImageResource(stub_id);
	    }
	}
	
	public void clearCache()
	{
	    memoryCache.clear();
	    fileCache.clear();
	}
	
    }
    
    public class FileCache
    {
	
	private File cacheDir;
	
	public FileCache(Context context)
	{
	    // Find the dir to save cached images
	    if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED))
		cacheDir = new File(android.os.Environment.getExternalStorageDirectory(), "ITV");
	    else
		cacheDir = context.getCacheDir();
	    if (!cacheDir.exists())
		cacheDir.mkdirs();
	}
	
	public File getFile(String url)
	{
	    // I identify images by hashcode. Not a perfect solution, good for
	    // the demo.
	    String filename = String.valueOf(url.hashCode());
	    // Another possible solution (thanks to grantland)
	    // String filename = URLEncoder.encode(url);
	    File f = new File(cacheDir, filename);
	    return f;
	    
	}
	
	public void clear()
	{
	    File[] files = cacheDir.listFiles();
	    if (files == null)
		return;
	    for (File f : files)
		f.delete();
	}
	
    }
    
}
